﻿using System;
using System.Drawing;
using Graphix.Elements;
using CommonHelpers;
namespace Graphix.Charts
{
    using System.Globalization;
    using Graphix.Charts.Base;

    public class ColumnChart : ColumnBase
    {
        protected override void AddBars()
        {
            float bottom = this.Border.Bottom - 1;
            float length = this.Border.Height - 1;
            float position;
            int groups = this.SetsName.Count;
            float width = this.Border.Width / groups;

            float barwidth = this.Border.Width / ((1 + (float)Math.Sqrt(5)) / 2);
            barwidth /= groups;

            float modifier = 1;

            if (!this.IsStacked)
            {
                barwidth /= this.BarSet.Count;
            }

            if (this.YAxis.OppositeDirection)
            {
                if (this.XAxis.OppositeDirection)
                {
                    if (this.IsStacked)
                    {
                        position = this.Border.Right - barwidth - ((width - barwidth) / 2f); // 1
                    }
                    else
                    {
                        position = this.Border.Right - ((width - ((barwidth + (1 * 2)) * this.BarSet.Count)) / 2f) - 1 - barwidth; //5
                    }
                }
                else
                {
                    if (this.IsStacked)
                    {
                        position = this.Border.Left + ((width - barwidth) / 2f); // 3
                    }
                    else
                    {
                        position = (this.Border.Right - ((width - ((barwidth + (1 * 2)) * this.BarSet.Count)) / 2f) - 1 - barwidth) - 7 * width; //7
                    }
                }
            }
            else
            {
                if (this.XAxis.OppositeDirection)
                {
                    if (this.IsStacked)
                    {
                        position = this.Border.Right - barwidth - ((width - barwidth) / 2f); // 2
                    }
                    else
                    {
                        position = this.Border.Right - width + (((width - barwidth * this.BarSet.Count) - (this.BarSet.Count * 2f)) / 2f) + 1; //6
                    }
                }
                else
                {
                    if (this.IsStacked)
                    {
                        position = this.Border.Left + 1 + ((width - barwidth) / 2f); // 4
                    }
                    else
                    {
                        position = this.Border.Right - width + (((width - barwidth * this.BarSet.Count) - (this.BarSet.Count * 2f)) / 2f) - 7 * width; //8
                    }
                }
            }

            if (this.YAxis.OppositeDirection)
            {
                modifier = -1;
            }

            float space = 1;
            
            if (this.IsStacked)
            {
                float[] positionY = new float[this.BarSet[0].Values.Count];
                for (int i = 0; i < this.BarSet.Count; i++)
                {
                    ValueSet<float> information = this.BarSet[i];
                    for (int j = 0; j < information.Values.Count; j++)
                    {
                        float value = information.Values[j];
                        float percent = value / this.YAxis.Scale.NiceMax;

                        float temp;
                        float temppos;
                        if (XAxis.OppositeDirection)
                        {
                            temppos = position - (width * j);
                        }
                        else
                        {
                            temppos = position + (width * j);
                        }

                        if (YAxis.OppositeDirection)
                        {
                            temp = this.Border.Top;
                        }
                        else
                        {
                            temp = bottom - (length * percent);
                        }
                        var element = new Rect(temppos, temp - positionY[j], barwidth,
                            length * percent, information.Color);
                        element.Attributes["g"] = i.ToString(CultureInfo.InvariantCulture);
                        string legend = this.SetsName[j];
                        if (string.IsNullOrEmpty(legend))
                        {
                            legend = " ";
                        }
                        element.Attributes["data-ot"] =
                            string.Format(CultureInfo.InvariantCulture,
                                          "l={0};v={{\"{1}\": \"{2}\"}}",
                                          legend, information.Name, value);
                        this.AddElement(element);

                        positionY[j] += ((length * percent) + space + 1) * modifier;
                    }
                }
            }
            else
            {
                for (int i = 0; i < this.BarSet.Count; i++)
                {
                    ValueSet<float> information = this.BarSet[i];
                    for (int j = 0; j < information.Values.Count; j++)
                    {
                        float value = information.Values[j];
                        float percent = value / this.YAxis.Scale.NiceMax;

                        float temp;
                        float temppos;
                        if (XAxis.OppositeDirection)
                        {
                            temppos = position - (width * j);
                        }
                        else
                        {
                            temppos = position + (width * j);
                        }

                        if (YAxis.OppositeDirection)
                        {
                            temp = this.Border.Top;
                        }
                        else
                        {
                            temp = bottom - (length * percent);
                        }

                        var element = new Rect(temppos, temp, barwidth,
                            length * percent,
                            information.Color);

                        element.Attributes["g"] = j.ToString(CultureInfo.InvariantCulture);
                        string legend = this.SetsName[j];
                        if (string.IsNullOrEmpty(legend))
                        {
                            legend = " ";
                        }
                        element.Attributes["data-ot"] = 
                            string.Format(CultureInfo.InvariantCulture,
                                          "l={0};v={{\"{1}\": \"{2}\"}}",
                                          legend, information.Name, value);
                        this.AddElement(element);
                    }

                    position += (barwidth + space + 1) * modifier;
                }
            }
        }

        protected virtual void AddXAxisTicks()
        {
            if (BarSet.Count > 0 && this.XAxis.DisplayValues)
            {
                float left = this.Border.Left;
                float step = this.Border.Width / this.SetsName.Count;

                float modifier = 1;
                if (this.XAxis.OppositeDirection)
                {
                    modifier = -1;
                    left = this.Border.Right;
                }
                
                for (int i = 0; i < this.SetsName.Count; i++)
                {
                    float position = left + ((step * (i + 0.5f)) * modifier);
                    string text = this.SetsName[i];
                    text = string.Format(this.XAxis.Format, text);

                    this.AddElement(new ChartString(position, this.Border.Bottom, 0, 0, text,
                        this.XAxis.TextStyle.Font, this.XAxis.TextStyle.ColorBrush)
                        { Format = new StringFormat() { Alignment = StringAlignment.Center } });
                }
            }
        }

        protected virtual void AddYAxisTicks()
        {
            this.YAxis.CalculateScale();
            int loop = (int)((this.YAxis.Scale.NiceMax - this.YAxis.Scale.NiceMin) / this.YAxis.Scale.TickSpacing);

            if (this.YAxis.DisplayValues)
            {
                string longest =
                    string.Format("{0:### ### ### ### ### ##0}", this.YAxis.Scale.NiceMax).TrimStart();
                RectangleF measured = DefaultGraphics.Instance.MeasureDisplayString(longest,
                    new Font(FontFamily.GenericMonospace, 10));
                this.Border.Left += measured.Width;
            }

            float left = this.Border.Left;
            float step = this.Border.Height / loop;
            float right = this.Border.Right;
            float bottom = this.Border.Bottom;

            for (int i = 0; i <= loop; i++)
            {
                var alignment = StringAlignment.Center;
                if (i == 0)
                {
                    alignment = StringAlignment.Far;
                }
                else if (i >= loop)
                {
                    alignment = StringAlignment.Near;
                }

                float position = bottom - (step * i);

                Pen color = i == 0 ? this.YAxis.MajorColor : this.YAxis.MinorColor;

                float value;
                if (this.YAxis.OppositeDirection)
                {
                    value = this.YAxis.Scale.TickSpacing * (loop - i);
                }
                else
                {
                    value = this.YAxis.Scale.TickSpacing * i;
                }

                this.AddElement(new Line(left, position, right, position, color));

                if (this.YAxis.DisplayValues)
                {
                    string text = string.Format(this.YAxis.Format, value);

                    this.AddElement(new ChartString(left - 2, position, 0, 0, text,
                        this.YAxis.TextStyle.Font, this.YAxis.TextStyle.ColorBrush)
                        {
                            Format =
                                new StringFormat()
                                    {
                                        Alignment = StringAlignment.Far,
                                        LineAlignment = alignment
                                    }
                        });
                }
            }
        }

        protected override void AddTicks()
        {
            if (this.XAxis.DisplayValues)
            {
                this.Border.Bottom -=
                    DefaultGraphics.Instance.MeasureDisplayString("|", this.XAxis.TextStyle.Font).Height;
            }
            this.AddYAxisTicks();
            this.AddXAxisTicks();
        }
    }
}
